#include <iostream>
using std::cin; using std::cout; using std::endl; using std::cerr;
#include <string>
using std::string;

class Token{
public:
    //因为union含有一个string成员，所以Token必须定义拷贝控制成员
    Token() : tok(INT), ival{0} {}
    Token(const Token &t) : tok(t.tok) { copyUnion(t); }    //拷贝构造函数
    Token &operator=(const Token &);        //拷贝赋值运算符
    Token(const Token &&t) noexcept : tok(std::move(t.tok)) { copyUnion(t); }    //移动构造函数
    Token &operator=(const Token &&) noexcept ;   //移动赋值运算符
    //如果union含有一个string成员，则我们必须销毁它
    ~Token() { if (tok == STR) sval.~string(); }
    //重载的赋值运算符负责设置union的不同成员
    Token &operator=(const string &);
    Token &operator=(char);
    Token &operator=(int);
    Token &operator=(double);
private:
    enum {INT,CHAR, DBL, STR} tok;  //判别式
    union { //匿名union
        char cval;
        int ival;
        double dval;
        string sval;
    };  //每个Token对象含有一个该未命名union类型的未命名成员
    //检查判别式，然后酌情拷贝union成员
    void copyUnion(const Token &);
};

Token& Token::operator=(int i) {
    if (tok == STR) sval.~string(); //如果当前存储的是string，释放它
    ival = i;
    tok = INT;
    return *this;
}

Token& Token::operator=(const string &s) {
    if (tok == STR)     //如果当前存储的是string，则可以直接赋值
        sval = s;
    else
        new (&sval) string(s);  //否则需要先构造一个string
    tok = STR;  //更新判别式
    return *this;
}

void Token::copyUnion(const Token &t) {
    switch (t.tok){
        case Token::INT:    ival = t.ival;  break;
        case Token::CHAR:   cval = t.cval;  break;
        case Token::DBL:    dval = t.dval;  break;
        case Token::STR:    new (&sval) string(t.sval); break;
    }
}

Token& Token::operator=(const Token &rhs) {
    //如果*this的值是string而rhs的值不是，必须释放原有的string
    if (tok == STR && rhs.tok != STR) sval.~string();
    //若二者都是string，可直接赋值
    if (tok == STR && rhs.tok == STR)
        sval = rhs.sval;
    else
        copyUnion(rhs); //*this->tok不是STR而rhs是，需要构造新的string
    tok = rhs.tok;
    return *this;
}

Token& Token::operator=(const Token &&rhs) noexcept {
    if (this != &rhs){  //检测自赋值
        //如果*this的值是string而rhs的值不是，必须释放原有的string
        if (tok == STR && rhs.tok != STR) sval.~string();
        //若二者都是string，可直接赋值
        if (tok == STR && rhs.tok == STR)
            sval = std::move(rhs.sval);
        else
            copyUnion(rhs); //*this->tok不是STR而rhs是，需要构造新的string
        tok = std::move(rhs.tok);
    }
    return *this;
}

Token &Token::operator=(char c) {
    if (tok == STR) sval.~string(); //如果当前存储的是string，释放它
    cval = c;
    tok = CHAR;
    return *this;
}

Token &Token::operator=(double d) {
    if (tok == STR) sval.~string(); //如果当前存储的是string，释放它
    dval = d;
    tok = DBL;
    return *this;
}

int main() {}